/*
 * PhotonRTOS础光实时操作系统 -- 调度
 *
 * Copyright (C) 2022, 2023 国科础石(重庆)软件有限公司
 *
 * 作者: Baoyou Xie <xiebaoyou@kernelsoft.com>
 *
 * License terms: GNU General Public License (GPL) version 3
 *
 */

#ifndef _OS_SCHED_H
#define _OS_SCHED_H

#ifdef __KERNEL__
#include <photon/process.h>
#include <photon/double_list.h>
#include <photon/smp_lock.h>
#include <photon/time.h>
#include <photon/cpu.h>
#include <photon/smp.h>
#include <asm/internel.h>

#include <autosar/const.h>
#include <autosar/task.h>
#include <autosar/alarm.h>

/**
 * 任务标志
 */
enum {
	/**
	 * 系统IDLE任务
	 */
	__TF_IDLE,
	/**
	 * OSEK基本任务
	 */
	__TF_BASE	= 0,
	/**
	 * OSEK扩展任务
	 */
	__TF_EXTENDED,

};

#define TF_IDLE (1U << __TF_IDLE)
#define TF_BASE (1U << __TF_BASE)
#define TF_EXTENDED (1U << __TF_EXTENDED)

#define TF_OSEK (TF_BASE | TF_EXTENDED)
#define INVALID_OSEK_ID (0xFFFFUL)

#define SCHED_FIFO	0
#define SCHED_TIMESLICE	1
#define SCHED_NORMAL	2
#define SCHED_SERVICE	3

struct async_event {
	uintptr_t event_mask;
};

struct autosar_cp_attr {
	/**
	 * 想要异步激活当前cp任务的 task.
	 */
	uint8 async_activate_caller[OS_NR_TASK/8 + !!(OS_NR_TASK%8)];
	/**
	 * 作为cp任务被激活的时间点
	*/
	uint64_t cp_active_time;

	/**
	 * 距离上一次激活任务的最短时间限制
	*/
	uint64_t cp_task_time_frame;

	/**
	 * 两次2类中断发生的最短时间间隔
	*/
	uint64_t cp_isr_time_frame;

	/**
	 * cp 任务的实际执行时间
	*/
	uint64_t cp_task_execution_time;

	/**
	 * cp 任务的开始时间点
	*/
	uint64_t cp_task_start_point;

	/**
	 * cp 任务的预算总执行时间
	*/
	uint64_t cp_task_execution_budget;

	/**
	 * cp 中断处理程序ISR的预算总执行时间
	*/
	uint64_t cp_isr_execution_budget;

	/**
	 * 想要异步给当前任务设置event的task.
	 */
	struct async_event async_set_event_caller[OS_NR_TASK];

	/**
	 * 当前可访问的地址空间
	 */
	uintptr_t prot_addr_start, prot_addr_end;
};

/**
 * 任务描述符
 */
struct task_desc {
	/**
	 * 魔法值
	 */
	int32_t			magic;
	/**
	 * 任务当前状态，如SUSPEND  最大值为SUSPENDED (1 << 4)
	 */
	volatile uint8_t		state:5;
	/**
	 * 当前任务是否是 autosar cp任务的标志
	 */
	volatile uint8_t		is_autosar_task:1;
	/**
	 * 是否在运行队列中
	*/
	uint8_t		in_run_queue:1;
	/**
	 * 是否自动启动
	*/
	uint8_t		auto_start:1;
	/**
	 * 应用模式
	 */
	uint8_t		app_mode:2;
	/**
	 * 启动核心ID
	 */
	uint8_t		core_id:3;

	/**
	 * 任务调度优先级，当前按此优先级进行调度
	 * 可能比创建时的优先级有所提高或者降低
	 */
	uint16_t		sched_prio;
	/**
	 * 任务优先级，创建时的优先级
	 */
	uint16_t		prio;
	/**
	 * 堆栈的总大小
	 */
	uint16_t		stack_size;
	/**
	 * 持有的资源数量
	 */
	uint16_t		resource_count;
	/**
	 * 该任务最多可以激活的次数
	 */
	uint16_t		max_activate_count;
	/**
	 * 激活次数
	 * 对于基本任务来说，可以激活多次
	 */
	uint16_t		activate_count;

	/**
	 * 任务标志
	 */
	uint32_t		flags;

	/**
	 * 任务堆栈，即process_desc描述符
	 */
	void		*stack;
	/**
	 * 线程主函数
	 */
	void		(*task_main)(void);

	/**
	 * 任务入口函数
	 */
	void (*entry)(void);

	/**
	 * 临时变量，有点奇怪
	 * 用于释放描述符，以后会废弃
	 */
	struct task_desc		*prev_sched;
	/**
	 * 事件掩码，已经发送但是还没有被任务处理的事件
	 */
	uintptr_t event_mask;
	/**
	 * 正在等待的事件
	 */
	uintptr_t event_wait;
	/**
	 * 资源掩码，已经获取的资源
	 */
	uintptr_t resource_mask;
	/**
	 * autosar application id
	 */
	uint16_t app_id;
	/**
	 * OSEK编号
	 */
	uintptr_t osek_id;
	/**
	 * 已运行时间或相对开始时间
	 * 对于非正在运行的任务，总运行时间 = jiffies64
	 * 对于正在运行的任务，总运行时间 = now - jiffies64
	 */
	uint64_t		jiffies64;
	/**
	 * 通过此字段将任务放进运行队列
	 */
	struct double_list		run_list;
	/**
	 * 通过此字段将任务放进全局链表
	 */
	struct double_list		all_list;
	/**
	 * 任务调度\恢复的寄存器现场
	 */
	struct task_spot		task_spot;
	/**
	 * autosar cp 任务相关属性
	*/
	struct autosar_cp_attr cp_attr;
	/**
	 * 任务每次执行的tick数
	 */
	int live_tick;
	/**
	 * 任务调度策略
	 */
	int			sched_policy;
};

#define TASK_MAX_PRIORITY (CONFIG_OSEK_MAX_TASK_PRIO - 1)

/**
 * 从静态数组中初始化任务
 */
extern void sched_init_task(uint32_t id);
/**
 * 从静态数组中激活任务
 */
extern void sched_activate_task(int32_t id);
/**
 * 从静态数组中去激活任务
 */
extern void sched_deactivate_task(int32_t id);
/**
 * 调整任务优先级
 */
extern void sched_task_change_prio(TaskType task_id, uint32_t prio);
/**
 * yield调用
 */
extern void sched_yield(void);
/**
 * 唤醒OSEK任务
 */
extern void sched_task_wakeup(TaskType task_id);


extern struct osek_task_attr *osek_task_attrs[OS_NR_TASK];
extern struct task_desc osek_tasks[OS_NR_TASK];

extern union process_union osek_stacks[OS_NR_TASK];
extern struct osek_alarm_attr *osek_alarm_attrs[OS_NR_ALARM];

/**
 * 全局静态的任务堆栈，用于boot cpu的idle进程
 * 避免在系统启动阶段分配内存
 */
extern union process_union master_idle_stack;

extern struct task_desc idle_task_desc[MAX_CPUS];
static inline struct task_desc *idle_task(int32_t cpu)
{
	return &idle_task_desc[cpu];
}

static inline void
__set_task_state(struct task_desc *tsk, uintptr_t state)
{
	tsk->state = state;
}

/**
 * 设置进程状态。同时会加上内存屏障。
 */
static inline void
set_task_state(struct task_desc *tsk, uintptr_t state)
{
	tsk->state = state;
}

/**
 * 设置当前进程状态。无内存屏障。
 */
static inline void
__set_current_state(uintptr_t state)
{
	current->state = state;
}

/**
 * 设置当前进程状态。同时会加上内存屏障。
 */
static inline void
set_current_state(uintptr_t state)
{
	set_task_state(current, state);
}

#define task_process_info(task)	((struct process_desc *)(task)->stack)
#define task_stack_bottom(task)	((task)->stack)

static inline int32_t test_task_proc_flag(struct task_desc *tsk, int32_t flag)
{
	return __test_process_flag(task_process_info(tsk), flag);
}

static inline void set_task_proc_flag(struct task_desc *tsk, int32_t flag)
{
	__set_process_flag(task_process_info(tsk), flag);
}

static inline void set_task_need_resched(struct task_desc *tsk)
{
	set_task_proc_flag(tsk, PROCFLAG_NEED_RESCHED);
}

static inline void clear_task_need_resched(struct task_desc *tsk)
{
	__clear_process_flag(task_process_info(tsk), PROCFLAG_NEED_RESCHED);
}

static inline void set_task_activate_async_flag(struct task_desc *tsk)
{
	set_task_proc_flag(tsk, PROCFLAG_ACTIVATE_ASYNC_FLAG);
}

static inline void clear_task_activate_async_flag(struct task_desc *tsk)
{
	__clear_process_flag(task_process_info(tsk), PROCFLAG_ACTIVATE_ASYNC_FLAG);
}

static inline int32_t task_need_async_activate(struct task_desc *tsk)
{
	return test_task_process_flag(task_process_info(tsk), PROCFLAG_ACTIVATE_ASYNC_FLAG);
}

static inline void set_task_event_async_flag(struct task_desc *tsk)
{
	set_task_proc_flag(tsk, PROCFLAG_SET_EVENT_ASYNC_FLAG);
}

static inline void clear_task_event_async_flag(struct task_desc *tsk)
{
	__clear_process_flag(task_process_info(tsk), PROCFLAG_SET_EVENT_ASYNC_FLAG);
}

static inline int32_t task_need_async_set_event(struct task_desc *tsk)
{
	return test_task_process_flag(task_process_info(tsk), PROCFLAG_SET_EVENT_ASYNC_FLAG);
}

static inline int32_t core_need_activate(void)
{
	return osek_core_if_activate[smp_processor_id()];
}

static inline void set_core_need_activate(int32_t core_id)
{
	osek_core_if_activate[core_id] = 1;
}

static inline void clear_core_activate(void)
{
	osek_core_if_activate[smp_processor_id()] = 0;
}

static inline int32_t core_need_set_event(void)
{
	return osek_core_if_set_event[smp_processor_id()];
}

static inline void set_core_need_set_event_flag(int32_t core_id)
{
	osek_core_if_set_event[core_id] = 1;
}

static inline void clear_core_set_event_flag(void)
{
	osek_core_if_set_event[smp_processor_id()] = 0;
}

static inline int32_t need_resched(void)
{
	return (test_process_flag(PROCFLAG_NEED_RESCHED));
}

/**
 * 全局任务链表
 */

extern struct double_list sched_all_task_list_table[];

#if MAX_CPUS > 1
extern union process_union slave_idle_stack[MAX_CPUS - 1];
#endif


#define sched_all_task_list	(sched_all_task_list_table[smp_processor_id()])

extern asmlinkage void schedule(void);
extern asmlinkage void preempt_in_irq(void);

/**
 * 模块初始化函数
 *	init_sched_early:早期初始化，只能使用bootmem分配
 *	init_sched:初始化
 */
extern void init_sched_early(void);
extern void init_sched(void);

extern void cpu_idle(void);

void dump_stack(void);

void del_from_runqueue(struct task_desc *p);

#endif /* __KERNEL__ */

#endif /* _OS_SCHED_H */
